package gebze;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import param.Parametre;

/**
 *
 * @author handan
 */
public class GbzServer {

    private int portNo = 1234;
    private Socket soket = null;
    private InputStream inputStream = null;

    public byte[] getDataFromClient(String ip) {
        boolean sonuc = baglan(ip);
        byte[] veri = null;
        if (sonuc == true) {
            veri = getImageFromClient();
        }
        return veri;
    }

    private boolean baglan(String ip) {
        try {
            soket = new Socket(ip, portNo);
            inputStream = soket.getInputStream();
        } catch (UnknownHostException ex) {
            Logger.getLogger(GbzServer.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        } catch (IOException ex) {
            Logger.getLogger(GbzServer.class.getName()).log(Level.SEVERE, null, ex);
            return false;
        }
        return true;
    }

    /**
     * Clienttan gelen parcalanmış datayı okur ve header numarasına gore
     * birleştirir.
     *
     * @return
     */
    private byte[] getImageFromClient() {
        byte[] originalData = null;
        int gelecekDosyaBoyutu = 0, tekrarSayisi = 0, artanMiktar = 0;

        try {
            gelecekDosyaBoyutu = inputStream.read();
        } catch (IOException ex) {
            System.out.println("Clienttan veriler okunamadi. ");
            return originalData;
        }

        tekrarSayisi = gelecekDosyaBoyutu / Parametre.MAX_DATA_PARCA_BOYUTU;
        artanMiktar = gelecekDosyaBoyutu % Parametre.MAX_DATA_PARCA_BOYUTU;
        originalData = new byte[gelecekDosyaBoyutu];
        for (int i = 0; i < tekrarSayisi; i++) {
            originalData = parcaOkuBirlestir(originalData, Parametre.MAX_PARCA_BOYUTU);
        }
        if (artanMiktar != 0) {
            originalData = parcaOkuBirlestir(originalData, artanMiktar + Parametre.PARCA_HEADER_SIZE);
        }
        return originalData;
    }

    /**
     * gelen byte dizisine ait header bilgisini cikararak orjinal veri dizisini
     * dondurur.
     *
     * @param okunanParca
     * @return
     */
    private byte[] getOriginalParca(byte[] okunanParca) {
        byte[] retValue = null;

        retValue = new byte[okunanParca.length - Parametre.PARCA_HEADER_SIZE];
        int baslangic_degeri = 0;
        for (int i = Parametre.PARCA_HEADER_SIZE; i < okunanParca.length; i++) {
            retValue[baslangic_degeri++] = okunanParca[i];
        }
        return retValue;
    }

    /**
     *
     * Kaynak dizinin elemanlarını, verilen parca sirasina gore hedef arraye
     * atar.
     *
     * @param hedefArray
     * @param kaynakArray
     * @param parcaSirasi
     * @return
     */
    private byte[] setParcaBirlestir(byte[] hedefArray, byte[] kaynakArray, int parcaSirasi) {
        int index = parcaSirasi * Parametre.MAX_DATA_PARCA_BOYUTU;
        for (int j = 0; j < kaynakArray.length; ++j) {
            hedefArray[index++] = kaynakArray[j];
        }
        return hedefArray;
    }

    /**
     * Inputstreamden lenght kadar veriyi okur, header bilgisni çıkarıp olusan
     * veriyi, parametre olarak gelen diziye ekler
     *
     *
     * @param originalData
     * @param length
     * @return
     */
    private byte[] parcaOkuBirlestir(byte[] originalData, int length) {
        byte[] okunanParca = new byte[length];
        byte[] originalParca = new byte[length - Parametre.PARCA_HEADER_SIZE];
        try {
            inputStream.read(okunanParca);

        } catch (IOException ex) {
            System.out.println("Parca okunamadi.");
        }
        int headerNo = Convert32BitsToInt(okunanParca, 0);
        originalParca = getOriginalParca(okunanParca);
        originalData = setParcaBirlestir(originalData, originalParca, headerNo);
        return originalData;

    }

    /**
     * Verilen byte dizisine ait header bilgisini okuyarak, headerı geri
     * dondurur.
     *
     * @param b
     * @param offset
     * @return
     */
    private int Convert32BitsToInt(byte[] b, int offset) {
        int value = 0;
        for (int i = 0; i < 4; i++) {
            int k = (4 - 1 - i) * 8;
            value += (b[i + offset] & 0x000000FF) << k;
        }
        return value;
    }
}
